package tilegame;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.io.*;
import java.util.ArrayList;
import javax.swing.ImageIcon;

import graphics.*;
import tilegame.sprites.*;

/**
The ResourceManager class loads and manages tile Images and
"host" Sprites used in the game. Game Sprites are cloned from
"host" Sprites.
 */
public class ResourceManager {

    private ArrayList tiles;
    private int currentMap;
    private GraphicsConfiguration gc;
    // host sprites used for cloning
    private Sprite playerSprite;
    private Sprite wangLife;
    private Sprite wangStrength;
    private Sprite wangScore;
    private Sprite wangGoal;
    private Sprite girlSprite;
    private Sprite boySprite;
    private Sprite negroSprite;
    private Sprite bossSprite;
    private Sprite shotSprite;

    /**
    Creates a new ResourceManager with the specified
    GraphicsConfiguration.
     */
    public ResourceManager(GraphicsConfiguration gc) {
        this.gc = gc;
        loadTileImages();
        loadCreatureSprites();
        loadPowerUpSprites();
    }

    /**
    Gets an image from the images/ directory.
     */
    public Image loadImage(String name) {
        String filename = "images/" + name;
        return new ImageIcon(filename).getImage();
    }

    public Image getMirrorImage(Image image) {
        return getScaledImage(image, -1, 1);
    }

    public Image getFlippedImage(Image image) {
        return getScaledImage(image, 1, -1);
    }

    private Image getScaledImage(Image image, float x, float y) {

        // set up the transform
        AffineTransform transform = new AffineTransform();
        transform.scale(x, y);
        transform.translate(
                (x - 1) * image.getWidth(null) / 2,
                (y - 1) * image.getHeight(null) / 2);

        // create a transparent (not translucent) image
        Image newImage = gc.createCompatibleImage(
                image.getWidth(null),
                image.getHeight(null),
                Transparency.BITMASK);

        // draw the transformed image
        Graphics2D g = (Graphics2D) newImage.getGraphics();
        g.drawImage(image, transform, null);
        g.dispose();

        return newImage;
    }

    public int getLevel(){
        return currentMap;
    }

    public TileMap loadNextMap() {
        TileMap map = null;
        while (map == null) {
            currentMap++;
            try {
                map = loadMap(
                        "maps/map" + currentMap + ".txt");
            } catch (IOException ex) {
                if (currentMap == 1) {
                    // no maps to load!
                    return null;
                }
                currentMap = 0;
                map = null;
            }
        }
        return map;
    }

    public TileMap reloadMap() {
        try {
            return loadMap(
                    "maps/map" + currentMap + ".txt");
        } catch (IOException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private TileMap loadMap(String filename)
            throws IOException {
        ArrayList lines = new ArrayList();
        int width = 0;
        int height = 0;

        // read every line in the text file into the list
        BufferedReader reader = new BufferedReader(
                new FileReader(filename));
        while (true) {
            String line = reader.readLine();
            // no more lines to read
            if (line == null) {
                reader.close();
                break;
            }

            // add every line except for comments
            if (!line.startsWith("#")) {
                lines.add(line);
                width = Math.max(width, line.length());
            }
        }

        // parse the lines to create a TileEngine
        height = lines.size();
        TileMap newMap = new TileMap(width, height);
        for (int y = 0; y < height; y++) {
            String line = (String) lines.get(y);
            for (int x = 0; x < line.length(); x++) {
                char ch = line.charAt(x);

                // check if the char represents tile A, B, C etc.
                int tile = ch - 'A';
                if (tile >= 0 && tile < tiles.size()) {
                    newMap.setTile(x, y, (Image) tiles.get(tile));
                } // check if the char represents a sprite
                else if (ch == 'o') {
                    addSprite(newMap, wangScore, x, y);
                } else if (ch == '!') {
                    addSprite(newMap, wangStrength, x, y);
                } else if (ch == '*') {
                    addSprite(newMap, wangGoal, x, y);
                } else if (ch == '^') {
                    addSprite(newMap, wangLife, x, y);
                } else if (ch == '1') {
                    addSprite(newMap, girlSprite, x, y);
                } else if (ch == '2') {
                    addSprite(newMap, boySprite, x, y);
                } else if (ch == '3') {
                    addSprite(newMap, negroSprite, x, y);
                } else if (ch == '4') {
                    addSprite(newMap, bossSprite, x, y);
                }
            }
        }

        // add the player to the map
        Sprite player = (Sprite) playerSprite.clone();
        player.setX(TileMapRenderer.tilesToPixels(3));
        player.setY(TileMapRenderer.tilesToPixels(3));
        newMap.setPlayer(player);

        return newMap;
    }

    public void generateShot(TileMap map, int tileX, int tileY, int direction) {
        // clone the sprite from the "host"
        Sprite sprite = (Sprite) shotSprite.clone();

        float velocityX = 0;

        if (direction == 1) {
            velocityX += ((Shot) sprite).getMaxSpeed();
        } else {
            velocityX -= ((Shot) sprite).getMaxSpeed();
        }

        sprite.setVelocityX(velocityX);

        sprite.setX(tileX);
        sprite.setY(tileY);

        // add it to the map
        map.addSprite(sprite);
    }

    private void addSprite(TileMap map,
            Sprite hostSprite, int tileX, int tileY) {
        if (hostSprite != null) {
            // clone the sprite from the "host"
            Sprite sprite = (Sprite) hostSprite.clone();

            // center the sprite
            sprite.setX(
                    TileMapRenderer.tilesToPixels(tileX)
                    + (TileMapRenderer.tilesToPixels(1)
                    - sprite.getWidth()) / 2);

            // bottom-justify the sprite
            sprite.setY(
                    TileMapRenderer.tilesToPixels(tileY + 1)
                    - sprite.getHeight());

            // add it to the map
            map.addSprite(sprite);
        }
    }

    // -----------------------------------------------------------
    // code for loading sprites and images
    // -----------------------------------------------------------
    public void loadTileImages() {
        // keep looking for tile A,B,C, etc. this makes it
        // easy to drop new tiles in the images/ directory
        tiles = new ArrayList();
        char ch = 'A';
        while (true) {
            String name = "tile_" + ch + ".png";
            File file = new File("images/" + name);
            if (!file.exists()) {
                break;
            }
            tiles.add(loadImage(name));
            ch++;
        }
    }

    public void loadCreatureSprites() {

        Image[][] images = new Image[4][];

        // load left-facing images
        images[0] = new Image[]{
                    loadImage("shot.png"),
                    loadImage("player1.png"),
                    loadImage("player2.png"),
                    loadImage("player3.png"),
                    loadImage("girl1.png"),
                    loadImage("girl2.png"),
                    loadImage("girl3.png"),
                    loadImage("girl4.png"),
                    loadImage("girl5.png"),
                    loadImage("boy1.png"),
                    loadImage("boy2.png"),
                    loadImage("boy3.png"),
                    loadImage("boy4.png"),
                    loadImage("boy5.png"),
                    loadImage("negro1.png"),
                    loadImage("negro2.png"),
                    loadImage("negro3.png"),
                    loadImage("negro4.png"),
                    loadImage("negro5.png"),
                    loadImage("boss1.png"),
                    loadImage("boss2.png"),
                    loadImage("boss3.png"),
                    loadImage("boss4.png"),
                    loadImage("boss5.png")};

        images[1] = new Image[images[0].length];
        images[2] = new Image[images[0].length];
        images[3] = new Image[images[0].length];
        for (int i = 0; i < images[0].length; i++) {
            // right-facing images
            images[1][i] = getMirrorImage(images[0][i]);
            // left-facing "dead" images
            images[2][i] = getFlippedImage(images[0][i]);
            // right-facing "dead" images
            images[3][i] = getFlippedImage(images[1][i]);
        }

        // create creature animations
        Animation[] shotAnim = new Animation[4];
        Animation[] playerAnim = new Animation[4];
        Animation[] girlAnim = new Animation[4];
        Animation[] boyAnim = new Animation[4];
        Animation[] negroAnim = new Animation[4];
        Animation[] bossAnim = new Animation[4];
        for (int i = 0; i < 4; i++) {
            shotAnim[i] = createShotAnim(images[i][0]);
            playerAnim[i] = createPlayerAnim(
                    images[i][1], images[i][2], images[i][3]);
            girlAnim[i] = createEnemyAnim(
                    images[i][4], images[i][5], images[i][6], images[i][7], images[i][8]);
            boyAnim[i] = createEnemyAnim(
                    images[i][9], images[i][10], images[i][11], images[i][12], images[i][13]);
            negroAnim[i] = createEnemyAnim(
                    images[i][14], images[i][15], images[i][16], images[i][17], images[i][18]);
            bossAnim[i] = createEnemyAnim(
                    images[i][19], images[i][20], images[i][21], images[i][22], images[i][23]);
        }

        Animation[] deadBee = new Animation[2];
        deadBee[0] = new Animation();
        deadBee[1] = new Animation();
        deadBee[0].addFrame(loadImage("deadbee.png"), 100);
        deadBee[1].addFrame(getMirrorImage(loadImage("deadbee.png")), 100);

        Animation[] deadGirl = new Animation[2];
        deadGirl[0] = new Animation();
        deadGirl[1] = new Animation();
        deadGirl[0].addFrame(loadImage("deadgirl.png"), 100);
        deadGirl[1].addFrame(getMirrorImage(loadImage("deadgirl.png")), 100);

        Animation[] deadBoy = new Animation[2];
        deadBoy[0] = new Animation();
        deadBoy[1] = new Animation();
        deadBoy[0].addFrame(loadImage("deadboy.png"), 100);
        deadBoy[1].addFrame(getMirrorImage(loadImage("deadboy.png")), 100);

        Animation[] deadNegro = new Animation[2];
        deadNegro[0] = new Animation();
        deadNegro[1] = new Animation();
        deadNegro[0].addFrame(loadImage("deadnegro.png"), 100);
        deadNegro[1].addFrame(getMirrorImage(loadImage("deadnegro.png")), 100);

//        Animation deadBoss = new Animation();
//        deadGirl.addFrame(loadImage("deadgirl.png"), 100);

        // create creature sprites
        shotSprite = new Shot(shotAnim[0], shotAnim[1],
                shotAnim[2], shotAnim[3]);
        playerSprite = new Player(playerAnim[0], playerAnim[1],
                deadBee[0], deadBee[1]);
        girlSprite = new Girl(girlAnim[0], girlAnim[1],
                deadGirl[0], deadGirl[1]);
        boySprite = new Boy(boyAnim[0], boyAnim[1],
                deadBoy[0], deadBoy[1]);
        negroSprite = new Negro(negroAnim[0], negroAnim[1],
                deadNegro[0], deadNegro[1]);
        bossSprite = new Boss(bossAnim[0], bossAnim[1],
                bossAnim[2], bossAnim[3]);
    }

    private Animation createShotAnim(Image shot) {
        Animation anim = new Animation();
        anim.addFrame(shot, 150);
        return anim;
    }

    private Animation createPlayerAnim(Image player1,
            Image player2, Image player3) {
        Animation anim = new Animation();
        anim.addFrame(player1, 50);
        anim.addFrame(player2, 50);
        anim.addFrame(player3, 50);
        anim.addFrame(player2, 50);
        return anim;
    }

    private Animation createEnemyAnim(Image img1, Image img2, Image img3, Image img4, Image img5) {
        Animation anim = new Animation();
        anim.addFrame(img1, 150);
        anim.addFrame(img2, 150);
        anim.addFrame(img3, 150);
        anim.addFrame(img4, 150);
        anim.addFrame(img5, 150);
        anim.addFrame(img4, 150);
        anim.addFrame(img3, 150);
        anim.addFrame(img2, 150);
        return anim;
    }

    private void loadPowerUpSprites() {
        // create "goal" sprite
        Animation anim = new Animation();
        anim.addFrame(loadImage("wanglife1.png"), 150);
        anim.addFrame(loadImage("wanglife2.png"), 150);
        anim.addFrame(loadImage("wanglife3.png"), 150);
        anim.addFrame(loadImage("wanglife2.png"), 150);
        wangLife = new PowerUp.WangLife(anim);

        // create "star" sprite
        anim = new Animation();
        anim.addFrame(loadImage("wangscore1.png"), 100);
        anim.addFrame(loadImage("wangscore2.png"), 100);
        anim.addFrame(loadImage("wangscore3.png"), 100);
        anim.addFrame(loadImage("wangscore2.png"), 100);
        wangScore = new PowerUp.WangRapidShot(anim);

        // create "music" sprite
        anim = new Animation();
        anim.addFrame(loadImage("wangstrength1.png"), 150);
        anim.addFrame(loadImage("wangstrength2.png"), 150);
        anim.addFrame(loadImage("wangstrength3.png"), 150);
        anim.addFrame(loadImage("wangstrength2.png"), 150);
        wangStrength = new PowerUp.WangStrength(anim);

        anim = new Animation();
        anim.addFrame(loadImage("wanggoal1.png"), 100);
        anim.addFrame(loadImage("wanggoal2.png"), 100);
        anim.addFrame(loadImage("wanggoal1.png"), 100);
        anim.addFrame(loadImage("wanggoal3.png"), 100);
        wangGoal = new PowerUp.WangGoal(anim);
    }
}
